package com.notary.tx_live_plugin.util;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.util.Log;

import com.tencent.rtmp.TXLivePusher;

import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 * Created by lixinquan on 2019/7/22.
 */
public class VideoProcessListener implements TXLivePusher.VideoCustomProcessListener {

    private static int BITMAP_WIDTH = 416;
    private static final int BITMAP_HEIGHT = 64;
    ///单个字符大小
    private static final int TEXT_SIZE = 30;
    ///字符个数
    private static final int TEXT_LENGTH = 5 + (20/2);//5个中文字符加20个英文字符

    private long serverTime, mobileTime;
    private int mProgramWaterMask;
    int[] waterTexture = new int[1];
    private int[] fFrame;

    Paint paint = new Paint();
    Bitmap bm;

    private FloatBuffer waterVertexBuffer, waterTextureBuffer;

    public VideoProcessListener() {
        paint.setColor(0xffffffff);
        paint.setTextSize(TEXT_SIZE);
        String tmp = "北京时间 0000-00-00 00:00:00  ";
        Rect tmpRect = new Rect();
        paint.getTextBounds(tmp,0,tmp.length(),tmpRect);
        BITMAP_WIDTH = tmpRect.right - tmpRect.left + 10;
        serverTime = mobileTime = System.currentTimeMillis();
        Log.d("demo", "texture width "+BITMAP_WIDTH);
    }

    public void syncTime(long serverTime) {
        this.serverTime = serverTime;
        this.mobileTime = System.currentTimeMillis();
    }

    @Override
    public int onTextureCustomProcess(int textureId, int width, int height) {
        bindFrameTexture(width, height);
        Bitmap bm = buildWatermask();
        if(serverTime > 0) storeImage(bm, textureId, width, height);
        return textureId;
    }

    @Override
    public void onDetectFacePoints(float[] floats) {}

    @Override
    public void onTextureDestoryed() {
//        Logger.i("texture destory...");
        GLES20.glDeleteTextures(1, waterTexture, 0);
        if(fFrame != null) GLES20.glDeleteFramebuffers(1, fFrame, 0);
        GLES20.glDeleteProgram(mProgramWaterMask);
        fFrame = null;
        if(bm != null) bm.recycle();
    }

    private void bindFrameTexture(int width, int height) {
        if(fFrame != null) return;
        Log.d("demo", "init texture "+BITMAP_WIDTH + "," +BITMAP_HEIGHT);

        bm = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Bitmap.Config.ARGB_8888);
        fFrame = new int[1];
        waterTextureBuffer = allocateFloatBuffer(waterMaskTextureData);
        waterVertexBuffer = allocateFloatBuffer(waterMaskVertexData2);
        mProgramWaterMask = createProgram(waterVertexShader, waterFragmentShader);

        GLES20.glDeleteFramebuffers(1, fFrame, 0);
        GLES20.glDeleteTextures(1, waterTexture, 0);

        GLES20.glGenTextures(1, waterTexture, 0);
        /**创建一个帧染缓冲区对象*/
        GLES20.glGenFramebuffers(1,fFrame,0);
    }

    private void storeImage(Bitmap bitmap,int textureId, int screenWidth, int screenHeight) {
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fFrame[0]);
        GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, textureId, 0);

        int left = (screenWidth - BITMAP_WIDTH) / 2;
        //绘制水印
        GLES20.glEnable(GLES20.GL_BLEND);
        GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
        GLES20.glViewport(left, (int) (screenHeight * 0.1f), BITMAP_WIDTH, BITMAP_HEIGHT);

        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, waterTexture[0]);
        glTexParameter(false);
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

        drawGLTexture(mProgramWaterMask, waterTexture[0], waterTextureBuffer, waterVertexBuffer);
        GLES20.glDisable(GLES20.GL_BLEND);

        if(GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER) != GLES20.GL_FRAMEBUFFER_COMPLETE) {
//            Logger.w("ERROR::FRAMEBUFFER:: Framebuffer is not complete!");
        }
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,0);
    }

    private void drawGLTexture(int p, int texture, Buffer texureBuffer, Buffer vertextBuffer) {
//        Logger.v("draw waterTexture" , texture , p);
        GLES20.glUseProgram(p);

        int mPositionHandle = GLES20.glGetAttribLocation(p, "af_Position");
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        GLES20.glVertexAttribPointer(mPositionHandle, 2, GLES20.GL_FLOAT, false, 8, texureBuffer);
        //纹理坐标
        int mTextureCoordHandle = GLES20.glGetAttribLocation(p, "av_Position");
        GLES20.glEnableVertexAttribArray(mTextureCoordHandle);
        GLES20.glVertexAttribPointer(mTextureCoordHandle, 2, GLES20.GL_FLOAT, false, 8, vertextBuffer);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
        GLES20.glDisableVertexAttribArray(mPositionHandle);
        GLES20.glDisableVertexAttribArray(mTextureCoordHandle);
//        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
    }

    private Bitmap buildWatermask() {
        bm.eraseColor(0x00000000);
        Canvas canvas = new Canvas(bm);

        long ntime = System.currentTimeMillis() - mobileTime + serverTime;
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
        String time = format.format(new Date(ntime));
        String ts = String.format("北京时间 %s ", time);
        canvas.drawText(ts, 0, 40, paint);
        return bm;
    }

    static final String waterVertexShader =
            "attribute vec4 av_Position;" +
                    "attribute vec2 af_Position;" +
                    "varying vec2 v_texPo;" +
                    "void main() {" +
                    "    v_texPo = af_Position;" +
                    "    gl_Position = av_Position;" +
                    "}";

    static final String waterFragmentShader =
            "precision mediump float;" +
                    "varying vec2 v_texPo;" +
                    "uniform sampler2D sTexture;" +
                    "void main() {" +
                    "    gl_FragColor=texture2D(sTexture, v_texPo);" +
                    "}";

    public static int loadShader(int type, String shaderCode) {
        // 创造顶点着色器类型(GLES20.GL_VERTEX_SHADER)
        // 或者是片段着色器类型 (GLES20.GL_FRAGMENT_SHADER)
        int shader = GLES20.glCreateShader(type);
        // 添加上面编写的着色器代码并编译它
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);
        return shader;
    }

    public static int createProgram(String verTextShader, String fragmentShader) {
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, verTextShader);
        int fragShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);
        //创建一个空的OpenGLES程序
        int program = GLES20.glCreateProgram();
        //将顶点着色器加入到程序
        GLES20.glAttachShader(program, vertexShader);
        //将片元着色器加入到程序中
        GLES20.glAttachShader(program, fragShader);
        //连接到着色器程序
        GLES20.glLinkProgram(program);
        return program;
    }

    public static FloatBuffer allocateFloatBuffer(float[] vertices) {
        return allocateFloatBuffer(null, vertices);
    }

    public static FloatBuffer allocateFloatBuffer(FloatBuffer vertexBuffer, float[] vertices) {
        if(vertexBuffer == null) {
            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
            byteBuffer.order(ByteOrder.nativeOrder());
            vertexBuffer = byteBuffer.asFloatBuffer();
        } else {
            vertexBuffer.clear();
        }
        vertexBuffer.put(vertices);
        vertexBuffer.position(0);
        return vertexBuffer;
    }
    static void glTexParameter(boolean isOes) {
        int target = isOes ? GLES11Ext.GL_TEXTURE_EXTERNAL_OES : GLES20.GL_TEXTURE_2D;
        //设置缩小过滤为使用纹理中坐标最接近的一个像素的颜色作为需要绘制的像素颜色
        GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
        //设置放大过滤为使用纹理中坐标最接近的若干个颜色，通过加权平均算法得到需要绘制的像素颜色
        GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        //设置环绕方向S，截取纹理坐标到[1/2n,1-1/2n]。将导致永远不会与border融合
        GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        //设置环绕方向T，截取纹理坐标到[1/2n,1-1/2n]。将导致永远不会与border融合
        GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
    }
    static float waterMaskVertexData[] = {
            1f, -1f, // bottom right
            -1f, -1f, // bottom left
            1f, 1f,  // top right
            -1f, 1f, // top left
    };
    static float waterMaskVertexData2[] = {
            -1f, -1f, // bottom left
            1f, -1f, // bottom right
            -1f, 1f, // top left
            1f, 1f,  // top right
    };
    //纹理坐标  对应顶点坐标  与之映射
    static float waterMaskTextureData[] = {
            0f, 0f, // top left
            1f, 0f,  // top right
            0f, 1f, // bottom left
            1f, 1f, // bottom right
    };
}
